package core;

import java.util.List;

/**
 * Represents concrete instances of AbstractCards. All cards in a game are
 * represented by instances of this class. A Card also has a Visibility that
 * determines which Players are able to "see" the Card's name and attributes.
 * Card is the Concrete Flyweight in the GoF Flyweight pattern.
 */
public class Card extends GameObject
{
	public Card() {
		this(new CardIdentifier(null, null));
	}

	public Card(CardIdentifier id) {
		this(id == null ? null : id.getName(), id);
	}

	/**
	 * Create a new Card with the given name identifier and
	 * the given AbstractCard template. 
	 * Card objects in general.
	 * @param name a String identifier
	 * @param base an AbstractCard
	 */
	public Card(String name, CardIdentifier id) {
		super(name);
		setCardIdentifier(id);
	}

	// we purposefully don't use getters here so that visibility doesn't come into play
	public Card(Card card) {
		super(card.name);
		base = card.base;
		location = card.location;
		visibility = card.visibility;
		setAttributes(card.attributes);
	}

	/**
	 * Returns the Visibility setting of this Card.
	 */
	public Visibility getVisibility() {
		return visibility;
	}

	/**
	 * Sets the Visibility of this Card.
	 * @param v a Visibility setting
	 */
	public void setVisibility(Visibility v) {
		visibility = v;
	}

	public Location getLocation() {
		return location;
	}

	public void setLocation(Location location) {
		this.location = location;
		notifyObservers();
	}

	public String getName() {
		return isVisible() ? super.getName() : null;
	}

	/**
	 * Returns the AbstractCard prototype for this Card.
	 */
	public AbstractCard getBase() {
		return isVisible() ? base : module.SetLoader.FACE_DOWN_CARD;
	}

	public CardIdentifier getCardIdentifier() {
		return isVisible() ? new CardIdentifier(base.getSet(), base.getName()) : new CardIdentifier(null, null);
	}

	public void setCardIdentifier(CardIdentifier id) {
		this.base = module.SetLoader.getAbstractCard(id.getSet(), id.getName());
	}

	public List<Attribute> getAttributes() {
		return java.util.Collections.unmodifiableList(isVisible() ? attributes : new java.util.LinkedList<Attribute>());
	}

	public List<java.util.Collection<? extends GameObject>> getChildrens() {
		return java.util.Collections.unmodifiableList(isVisible() ? super.getChildrens() : new java.util.LinkedList<java.util.Collection<? extends GameObject>>());
	}

	public Zone getZone() {
		return zone;
	}

	public void setZone(Zone zone) {
		this.zone = zone;
	}

	private boolean isVisible() {
		return visibility == null || GameParticipantRegistry.get().getPlayer() == null || visibility.isVisibleTo(GameParticipantRegistry.get().getPlayer());
	}

	private AbstractCard base;
	private Visibility visibility = null;
	private Location location = null;
	private Zone zone = null;
}